01 - Wprowadzenie

Wprowadzenie do przetwarzania obrazów

Politechnika Poznańska, Instytut Robotyki i Inteligencji Maszynowej

Ćwiczenie laboratoryjne 1: Wstęp

Powrót do spisu treści ćwiczeń laboratoryjnych

Wstęp

Na zajęciach wykorzystywać będziemy język programowania Python oraz biblioteki dedykowane przetwarzaniu obrazów oraz – w mniejszym stopniu – uczeniu maszynowemu.

Python to język programowania wysokiego poziomu ogólnego przeznaczenia, o rozbudowanym pakiecie bibliotek standardowych, którego ideą przewodnią jest czytelność i klarowność kodu źródłowego. Jego składnia cechuje się przejrzystością i zwięzłością. Python wspiera różne paradygmaty programowania: obiektowy, imperatywny oraz w mniejszym stopniu funkcyjny. Posiada w pełni dynamiczny system typów i automatyczne zarządzanie pamięcią, będąc w tym podobnym do języków Perl, Ruby, Scheme czy Tcl. Podobnie jak inne języki dynamiczne jest często używany jako język skryptowy. Interpretery Pythona są dostępne na wiele systemów operacyjnych. Python rozwijany jest jako projekt Open Source zarządzany przez Python Software Foundation, która jest organizacją non-profit. Standardową implementacją języka jest CPython (napisany w C), ale istnieją też inne. (źródło: Wikipedia)

Kroki instalacji interpretera Pythona w systemie Windows

Rozwiń

Aby rozpocząć pracę z językiem Python należy pobrać jego interpreter.

Proszę pobrać dystrybucję Pythona w wersji 3.9.7 (najnowsza dostępna na dzień 2021.09.20):

https://www.python.org/ftp/python/3.9.7/python-3.9.7-amd64.exe

A następnie zainstalować. Na pierwszym ekranie należy zaznaczyć opcję: Add Python 3.9 to PATH

Pominięcie tej opcji uniemożliwi uruchomienie Pythona oraz jego narzędzi z konsoli, a także spowoduje, że IDE nie wykryje automatycznie lokalizacji interpretera.

Uwaga:
Po zainstalowaniu Pythona należy zrestartować komputer (w celu odświeżenia przez system zmiennej PATH).

Dodatkowe pakiety (biblioteki)

W celu instalacji dodatkowych bibliotek wykorzystane zostanie narzędzie pip obsługiwane przez wykorzystywane środowisko programistyczne. Biblioteki do zainstalowania: opencv-contrib-python, scikit-image, matplotlib Szczegóły przeprowadzenia tego procesu zostały omówione przy opisie tworzenia pierwszego projektu.


Kroki instalacji IDE PyCharm

Rozwiń

Na zajęciach wykorzystywane jest środowisko programistyczne PyCharm, które dostępne jest pod adresem:

https://www.jetbrains.com/pycharm/

Przy pierwszym uruchomieniu zostaną Państwo poproszeni o wybór schematu klawiszy (w przypadku przyzwyczajenia do skrótów klawiszowych z Visual Studio warto wybrać tę opcję) oraz schematu kolorów (np. Darcula).

Uwaga:
Po instalacji wszystkich elementów przy pisaniu programu w PyCharm powinny pokazywać się podpowiedzi dotyczące dostępnych funkcji. W celu ich wywołania należy wcisnąć Ctrl+Spacja po napisaniu kilku pierwszych liter. Aby podejrzeć argumenty wywoływanej funkcji, należy, mając kursor pomiędzy nawiasami nacisnąć Ctrl+Shift+Spacja. Możliwe jest również najechanie na funkcje wskaźnikiem myszki z wciśniętym klawiszem Ctrl.


Wykorzystywane biblioteki

Tworzenie pierwszego projektu w IDE

Rozwiń

Należy uruchomić PyCharm a następnie utworzyć nowy projekt. Okno podczas pierwszego uruchomienia przedstawiono poniżej. Przy kolejnych uruchomieniach ładowany będzie poprzedni projekt i w celu utworzenia nowego należy wybrać File->New Project.

Proszę zwrócić uwagę na nazwę oraz lokalizację projektu.

UWAGA

W nazwie oraz lokalizacji projektu zalecamy nie stosować polskich znaków diakrytycznych oraz spacji (używać podkreślników). Podczas tworzenia nowego projektu domyślnie wybrana jest opcja utworzenia nowego środowiska wirtualnego (virtualenv), które izoluje Państwa projekt i jest preferowanym podejściem (np. jedno środowisko wirtualne dla wszystkich projektów z przedmiotu). Różne wirtualne środowiska mogą zawierać różne biblioteki i/lub wersje tych samych bibliotek.

Na zajęciach w laboratorium, ze względów technicznych proszę jednak wybrać opcję Existing interpreter

Pierwsze uruchomienie skutkuje błędem i w celu jego eliminacji należy nacisnąć znajdujący się z prawej strony przycisk z trzema kropkami, a następnie wybrać System Interpreter (domyślna lokalizacja: C:\Users\lab\AppData\Local\Programs\Python\Python39\python.exe) jak na rysunku poniżej. Potwierdzić przyciskiem ok.

Ostatecznie okno tworzenia nowego projektu powinno wyglądać jak poniżej:

Przy pierwszym uruchomieniu (w laboratorium nie jest to konieczne, gdyż wszystko już jest zainstalowane) należy zainstalować dodatkowe biblioteki. W tym celu z menu File wybrać Settings, a następnie Project: i Project interpreter. Po prawej stronie znajduje się przycisk z plusem, który umożliwia instalację dodatkowych pakietów.

Należy następnie w okno wyszukiwania wpisywać i zainstalować następujące pakiety (poczekać do końca instalacji przed dodaniem kolejnej): matplotlib, opencv-contrib-python, scikit-image

Możemy teraz dodać nowy plik *.py i wkleić przykładowy program zamieszczony poniżej, uruchomić go i obserwować efekty działania.


Pierwszy program

Wklej do pliku main.py następujący kod. Uruchom i zaobserwuj efekty jego działania:

import cv2


def main():
    cap = cv2.VideoCapture(0)  # open the default camera

    key = ord('a')
    while key != ord('q'):
        # Capture frame-by-frame
        ret, frame = cap.read()

        # Our operations on the frame comes here
        # Convert RGB image to grayscale
        img_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        # Blur the image
        img_filtered = cv2.GaussianBlur(img_gray, (7, 7), 1.5)
        # Detect edges on the blurred image
        img_edges = cv2.Canny(img_filtered, 0, 30, 3)

        # Display the result of our processing
        cv2.imshow('result', img_edges)
        # Wait a little (30 ms) for a key press - this is required to refresh the image in our window
        key = cv2.waitKey(30)

    # When everything done, release the capture
    cap.release()
    # and destroy created windows, so that they are not left for the rest of the program
    cv2.destroyAllWindows()


if __name__ == '__main__':
    main()

Uwaga!
Zwróć uwagę na cyfrę 0 w linii cap = cv2.VideoCapture(0). Oznacza ona numer kamerki, która zostanie użyta do przechwytywania obrazu. W przypadku, gdybyśmy chcieli użyć innej kamerki, należy podać jej numer. W przypadku, gdybyśmy chcieli użyć pliku wideo, należy podać ścieżkę do pliku wideo.

Wczytywanie, zapisywanie i wyświetlanie obrazów

Znajdź w dokumentacji funkcje cv2.imread, cv2.imwrite oraz cv2.imshow.

Uwaga:
Funkcja cv2.imread jako drugi parametr przyjmuje flagę informującą o sposobie wczytywania obrazu. Flaga cv2.IMREAD_COLOR w przypadku wczytywania obrazu kolorowego oraz cv2.IMREAD_GRAYSCALE w przypadku obrazu w skali szarości. Szczegóły w dokumentacji: ImreadModes.

💥 Zadanie do wykonania 💥

Wyszukaj i pobierz z internetu dowolny obraz. Następnie, wczytaj go, wyświetl na ekranie i zapisz pod inną nazwą korzystając z powyższych funkcji. Znajdź nowo zapisany plik na dysku.

Uwaga:
Umieść obraz w tym samym katalogu co plik main.py lub podaj pełną ścieżkę do pliku.

Obrazy a piksele - przechowywanie obrazu w pamięci

Obraz wczytany z pliku lub pobrany z kamery przejwia pewne istotne cechy:

Poniżej zamieszczono wycinek obrazu wraz z wartościami jasności poszczególnych kanałów dla wszystkich pikseli w otoczeniu. Obraz kolorowy (BGR) - każdy piksel ma trzy kanały, czyli przechowuje trzy wartości:

Obraz w skali szarości (grayscale) - każdy piksel ma jeden kanał, czyli przechowuje jedną wartość:

Kształt macierzy przechowującej obraz po wczytaniu można sprawdzić za pomocą komend (obie działają identycznie):

print(np.shape(<nazwa_macierzy>))

print(<nazwa_macierzy>.shape)

💥 Zadanie do wykonania 💥

Przetestuj działanie powyższych funkcji na wczytanym obrazie (lub kilku obrazach).

💥 Zadanie do wykonania 💥

Zapoznaj się z informacjami dostępnymi pod linkiem, które dotyczą podstawowych operacji na macierzach obrazowych. Następnie korzystając z obraz …   Korzystając z obrazu z poprzedniego zadania, odczytaj wartość jasności piksela w położeniu 220, 270 kiedy obraz jest wczytany jako kolorowy oraz kiedy obraz jest wczytany w skali szarości. Zwróć uwagę na liczbę otrzymywanych wartości.

Uwaga:
W celu połączenia zmiennych z istniejącym tekstem można wykorzystać tak zwane f-string: print(f'Pixel value at [220, 270]: {px}')

Zwróć uwagę na literę f przed cudzysłowem otwierającym ciąg tekstowy - powoduje ona, że kod wpisany wewnątrz ciągu tekstowego pomiędzy klamrami {} będzie wykonany jako kod Pythonowy i w jego miejsce zostanie wstawiona zwrócona wartość. Dla dociekliwych: dobre podsumowanie starszych i obecnych możliwości formatowania tekstu w języku Python znajduje się tutaj.

💥 Zadanie do wykonania 💥

Wycinając dowolny prostokąt (często nazywany obszarem zainteresowania - ROI), zduplikuj fragment obrazu, wyświetl go w osobnym oknie, a następnie wklej w inne miejsce oryginalnego obrazu.

💥 Zadanie do wykonania 💥

Wykorzystaj funkcję cv2.cvtColor i zmień format kolorów z domyślnego dla OpenCV BGR na szeroko używany RGB. Wyświetl oba obrazy za pomocą cv2.imshow). Zwróć uwagę, jak ta zmiana wypłynęła na obrazy.

Uwaga:
Skąd rozbieżność między światem RGB a formatem BGR w OpenCV? Odpowiedź możesz znaleźć w tym pytaniu.

💥 Zadanie do wykonania 💥

Pobierz obraz wyświetlony poniżej (prawy przycisk myszy -> “Zapisz grafikę jako…”). Korzystając z funkcji cv2.split podzielić obraz na trzy składowe i w trzech niezależnych oknach wyświetlić osobno składową czerwoną, niebieską oraz zieloną.

Funkcja cv2.split jest kosztowna obliczeniowo. Wykorzystaj wielowymiarowe indeksowanie numpy (slicing - preferowany sposób w Pythonie) do uzyskania tego samego efektu.

Obsługa kamer oraz wideo

Biblioteka OpenCV zapewnia identyczny interfejs dostępu do poszczególnych klatek obrazu dla kamer oraz plików wideo. W obu przypadkach wykorzystywana jest ta sama klasa cv2.VideoCapture, którą inicjalizujemy inną wartością, tj. numerem kamery lub nazwą pliku wideo. Dalsza obsługa jest w obu przypadkach identyczna. Zapoznaj się z przykładem.

💥 Zadanie do wykonania 💥

Jeśli komputer jest wyposażony w kamerę to otwórz ją i wczytuj kolejne klatki po naciśnięciu klawisza spacja.

💥 Zadanie do wykonania 💥

Pobierz plik wideo i wczytaj z niego kolejne klatki jak w przypadku kamery. Dodaj obsługę zdarzenia polegającego na wykryciu końca pliku. W tym celu wykorzystaj wartość true/false zwracaną przez metodę read klasy VideoCapture.

Zadania do samodzielnej realizacji

💥 Zadanie do wykonania 💥

Dla przypomnienia podstaw języka Python wykonaj zadania z interaktywnego notatnika: https://colab.research.google.com/drive/1h9ZuXPR-WKHT5giNJdlF6TAhPjRgSS0k?usp=sharing

💥 Zadanie do wykonania 💥

OpenCV nie jest jedyną biblioteką do przetwarzania obrazów w Pythonie. Inną, również popularną biblioteką jest scikit-image. Została ona napisana w języku Python jako dedykowana biblioteka do przetwarzania obrazów. Charakteryzuje ją bardzo bogata dokumentacja i zbiór przykładów.

Zapoznaj się z pierwszymi krokami oraz zbiorem przykładów.

💥 Zadanie do wykonania 💥

Zrealizować prosty pokaz zdjęć z wybranego folderu: wybór następnego/poprzedniego zdjęcia ma się odbywać za pomocą dwóch różnych klawiszy (np. q, w). Pokaz ma być cykliczny, np. po osiągnięciu ostatniego zdjęcia i wciśnięciu klawisza ‘następny’ wczytywać się ma pierwsze zdjęcie.